package transport

import (
	"fmt"
	"gitee.com/dreamwithouttrace/websocket-module/core"
	"log"
	"sync"
	"time"
)

// SharedSlice 共享切片，用于分片管理连接
type SharedSlice struct {
	lists      map[int64]*core.WebSocketConnection
	lock       sync.RWMutex
	onlinTotal int64
	boyTotal   int64
	girlTotal  int64
	noSexTotal int64
}

// NewSharedSlice 创建新的共享切片
func NewSharedSlice() *SharedSlice {
	return &SharedSlice{
		lists:      make(map[int64]*core.WebSocketConnection),
		onlinTotal: 0,
		boyTotal:   0,
		girlTotal:  0,
		noSexTotal: 0,
	}
}

// SexCount 统计性别数量
func (s *SharedSlice) SexCount() (int, int, int) {
	s.lock.RLock()
	defer s.lock.RUnlock()

	var boy, girl, noSex int
	for _, val := range s.lists {
		if val.GetUser().GetSex() == "1" {
			boy += 1
		} else if val.GetUser().GetSex() == "2" {
			girl += 1
		} else {
			noSex += 1
		}
	}
	return boy, girl, noSex
}

// Exists 检查用户是否存在
func (s *SharedSlice) Exists(userId int64) bool {
	s.lock.RLock()
	defer s.lock.RUnlock()

	_, exists := s.lists[userId]
	return exists
}

// Add 添加连接
func (s *SharedSlice) Add(wss *core.WebSocketConnection) {
	s.lock.Lock()
	defer s.lock.Unlock()

	s.lists[wss.GetUser().GetID()] = wss
	s.onlinTotal += 1
	if wss.GetUser().GetSex() == "1" {
		s.boyTotal += 1
	} else if wss.GetUser().GetSex() == "2" {
		s.girlTotal += 1
	} else {
		s.noSexTotal += 1
	}
}

// Remove 移除连接
func (s *SharedSlice) Remove(wss *core.WebSocketConnection) {
	s.lock.Lock()
	defer s.lock.Unlock()

	delete(s.lists, wss.GetUser().GetID())
	s.onlinTotal -= 1
	if wss.GetUser().GetSex() == "1" {
		s.boyTotal -= 1
	} else if wss.GetUser().GetSex() == "2" {
		s.girlTotal -= 1
	} else {
		s.noSexTotal -= 1
	}
}

// Clean 清理所有连接
func (s *SharedSlice) Clean() []int64 {
	s.lock.RLock()
	defer s.lock.RUnlock()

	var array []int64
	for _, val := range s.lists {
		_ = val.Close()
		array = append(array, val.GetUser().GetID())
	}

	s.lists = make(map[int64]*core.WebSocketConnection)
	return array
}

// sendAll 向所有连接发送消息
func (s *SharedSlice) sendAll(msg core.Message) {
	s.lock.RLock()
	defer s.lock.RUnlock()

	for _, val := range s.lists {
		_ = val.WriteMessage(msg)
	}
}

// Get 获取指定用户的连接
func (s *SharedSlice) Get(userId int64) *core.WebSocketConnection {
	s.lock.RLock()
	defer s.lock.RUnlock()

	ws, ok := s.lists[userId]
	if !ok {
		return nil
	}
	return ws
}

// ClientsAlias 获取客户端别名列表
func (s *SharedSlice) ClientsAlias() []map[string]interface{} {
	s.lock.RLock()
	defer s.lock.RUnlock()

	var array []map[string]interface{}
	for _, ws := range s.lists {
		var datum = make(map[string]interface{})
		datum["id"] = ws.GetUserID()
		datum["nickname"] = ws.GetUser().GetNickname()
		datum["avatar"] = ws.GetUser().GetAvatar()
		datum["sex"] = ws.GetUser().GetSex()
		array = append(array, datum)
	}
	return array
}

// Transport WebSocket传输管理器
type Transport struct {
	slices            []*SharedSlice
	isStop            bool
	waitGroup         sync.WaitGroup
	config            *core.Config
	onDisconnect      func(conn core.Connection, user core.User, role interface{})
	onMessage         func(conn core.Connection, user core.User, role interface{}, message []byte)
	onConnect         func(conn core.Connection) error
	onMinuteCallback  func(boyTotal, girlTotal, noSexTotal, total int64)
	onDeliveryFailure func(data core.Message)
}

// NewTransport 创建新的传输管理器
func NewTransport(config *core.Config) *Transport {
	return &Transport{
		slices:    instanceSharedSlice(config.SharedCount),
		waitGroup: sync.WaitGroup{},
		isStop:    false,
		config:    config,
	}
}

// SetCallbacks 设置回调函数
func (t *Transport) SetCallbacks(
	onDisconnect func(conn core.Connection, user core.User, role interface{}),
	onMessage func(conn core.Connection, user core.User, role interface{}, message []byte),
	onConnect func(conn core.Connection) error,
	onMinuteCallback func(boyTotal, girlTotal, noSexTotal, total int64),
	onDeliveryFailure func(data core.Message),
) {
	t.onDisconnect = onDisconnect
	t.onMessage = onMessage
	t.onConnect = onConnect
	t.onMinuteCallback = onMinuteCallback
	t.onDeliveryFailure = onDeliveryFailure
}

// GetWaitGroup 获取WaitGroup
func (t *Transport) GetWaitGroup() *sync.WaitGroup {
	return &t.waitGroup
}

// createDisconnectCallback 创建断开连接回调函数
func (t *Transport) createDisconnectCallback(wss *core.WebSocketConnection) func(conn core.Connection, user core.User, role interface{}) {
	return func(conn core.Connection, user core.User, role interface{}) {
		// 移除用户连接，减少在线用户数量
		t.Remove(wss)

		// 调用原有的断开连接回调
		if t.onDisconnect != nil {
			t.onDisconnect(conn, user, role)
		}
	}
}

// instanceSharedSlice 实例化共享切片
func instanceSharedSlice(sharedCount int64) []*SharedSlice {
	var sharedSlice []*SharedSlice
	var i int64
	for i = 0; i < sharedCount; i++ {
		sharedSlice = append(sharedSlice, NewSharedSlice())
	}
	return sharedSlice
}

// Stop 停止传输管理器
func (t *Transport) Stop(r bool) {
	t.isStop = r

	log.Println("关闭客户端连接队列")
	t.Clear()
	log.Println("关闭客户端断连队列")
	t.waitGroup.Wait()
	log.Println("关闭客户端队列处理完成")
}

// BatchPush 批量推送消息
func (t *Transport) BatchPush(msg core.Message) {
	for _, ws := range t.slices {
		ws.sendAll(msg)
	}
}

// Push 向指定用户推送消息
func (t *Transport) Push(userId int64, msg core.Message) {
	wss := t.slices[userId%t.config.SharedCount]
	conn := wss.Get(userId)
	if conn != nil {
		_ = conn.WriteMessage(msg)
	} else {
		t.onDeliveryFailure(msg)
	}
}

// AddSocketClient 添加Socket客户端
func (t *Transport) AddSocketClient(wss *core.WebSocketConnection) {
	defer func() {
		if err := recover(); err != nil {
			log.Println(err)
		}
	}()

	if t.isStop {
		log.Println("wss server is ", t.isStop)

		_ = wss.Close()
		return
	}

	// 设置回调，包括断开连接时移除用户
	wss.SetCallbacks(t.createDisconnectCallback(wss), t.onMessage, t.onConnect, t.onDeliveryFailure)

	t.slices[wss.GetUser().GetID()%t.config.SharedCount].Add(wss)

	wss.SetWaits(&core.Waits{})
	t.waitGroup.Add(1)

	// 启动连接处理
	go wss.Start(t.config.ReadTimeout * time.Second)
}

// Clear 清理所有连接
func (t *Transport) Clear() {
	log.Println("start clear connections...")
	for _, wss := range t.slices {
		wss.Clean()
	}
	log.Println("clear end...")
}

// GetClientLists 获取客户端列表
func (t *Transport) GetClientLists() []map[string]interface{} {
	var lists []map[string]interface{}
	for _, item := range t.slices {
		lists = append(lists, item.ClientsAlias()...)
	}
	return lists
}

// GetClientInfo 获取客户端信息
func (t *Transport) GetClientInfo(userId int64) core.User {
	var wss = t.slices[userId%t.config.SharedCount].Get(userId)
	if wss == nil {
		return nil
	}
	return wss.GetUser()
}

// Kick 踢出用户
func (t *Transport) Kick(memberId int64, socketId string) {
	t.kickLocalUser(memberId)
}

// kickLocalUser 踢出本地用户
func (t *Transport) kickLocalUser(userId int64) {
	conn := t.slices[userId%t.config.SharedCount].Get(userId)
	if conn != nil {
		conn.Kick()
	}
}

// Remove 移除连接
func (t *Transport) Remove(member *core.WebSocketConnection) {
	t.slices[member.GetUser().GetID()%t.config.SharedCount].Remove(member)
}

// Total 获取总连接数
func (t *Transport) Total() int64 {
	var total int64
	for _, v := range t.slices {
		total += v.onlinTotal
	}
	return total
}

// Lists 获取连接列表
func (t *Transport) Lists() map[int64]*core.WebSocketConnection {
	return map[int64]*core.WebSocketConnection{}
}

// OnlineUserInformationStatistics 在线用户信息统计
func (t *Transport) OnlineUserInformationStatistics() (int64, int64, int64) {
	var total int64
	var boyTotal int64
	var girlTotal int64
	var noSexTotal int64
	for _, v := range t.slices {
		total += v.onlinTotal
		boyTotal += v.boyTotal
		girlTotal += v.girlTotal
		noSexTotal += v.noSexTotal
	}
	t.onMinuteCallback(boyTotal, girlTotal, noSexTotal, total)
	return boyTotal, girlTotal, noSexTotal
}

// Exists 检查用户是否存在
func (t *Transport) Exists(userId int64) bool {
	return t.slices[userId%t.config.SharedCount].Exists(userId)
}

// Get 获取用户连接
func (t *Transport) Get(userId int64) *core.WebSocketConnection {
	return t.slices[userId%t.config.SharedCount].Get(userId)
}

// Alias 获取用户别名
func (t *Transport) Alias(userId int64) string {
	return fmt.Sprintf(fmt.Sprintf("%%0%sd", "19"), userId)
}
